package com.bmc.ccproblem.visulaization;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.bmc.ccproblem.Cable;
import com.bmc.ccproblem.CableComplexityProblem;
import com.bmc.ccproblem.DataCenter;
import com.bmc.ccproblem.DataPoint;
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;

@SuppressWarnings("serial")
public class DataCenterVisualizer extends JFrame {
    private static final String input = "6 a b|a e 2|e b 2|a c 0|c d 8|c d 8|d b 0"
            .replace('|', '\n');
    private JTextArea textArea;
    private mxGraphComponent inGraphComponent;
    private mxGraphComponent outGraphComponent;

    public DataCenterVisualizer() {
        super("BMC - Cable Complexity Problem");
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                createInputPanel(), createOuputPanel());
        splitPane.setResizeWeight(0.5);
        add(splitPane, BorderLayout.CENTER);
        runComplexityProblem();
    }

    private JPanel createInputPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory
                .createTitledBorder("Initial graph (change text area)"));
        textArea = new JTextArea(input);
        textArea.setPreferredSize(new Dimension(80, 0));
        textArea.getDocument().addDocumentListener(new DocumentListener() {
            public void removeUpdate(DocumentEvent e) {
                runComplexityProblem();
            }

            public void insertUpdate(DocumentEvent e) {
                runComplexityProblem();
            }

            public void changedUpdate(DocumentEvent e) {
                runComplexityProblem();
            }
        });
        panel.add(new JScrollPane(textArea), BorderLayout.WEST);

        inGraphComponent = new mxGraphComponent(new mxGraph());
        panel.add(inGraphComponent, BorderLayout.CENTER);

        return panel;
    }

    protected void runComplexityProblem() {
        try {
            DataCenter dataCenter = new DataCenter(textArea.getText());
            inGraphComponent.setGraph(tomxGraph(dataCenter));
            inGraphComponent.refresh();
            new CableComplexityProblem().solve(dataCenter, dataCenter.pointA(),
                    dataCenter.pointB());
            outGraphComponent.setGraph(tomxGraph(dataCenter));
            outGraphComponent.refresh();
            textArea.setForeground(Color.BLACK);
        }
        catch (Exception e) {
            e.printStackTrace();
            textArea.setForeground(Color.RED);
        }
    }

    private JPanel createOuputPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("Output"));
        outGraphComponent = new mxGraphComponent(new mxGraph());
        panel.add(outGraphComponent, BorderLayout.CENTER);
        return panel;
    }

    private mxGraph tomxGraph(DataCenter dataCenter) {
        mxGraph graph = new mxGraph();
        Object parent = graph.getDefaultParent();
        graph.getModel().beginUpdate();
        try {
            Map<DataPoint, Object> vertecies = new HashMap<DataPoint, Object>();
            for (DataPoint point : dataCenter.dataPoints())
                vertecies.put(point, graph.insertVertex(parent, null,
                        point.toString(), 0, 0, 60, 60));

            for (Cable cable : dataCenter.cables())
                graph.insertEdge(parent, null,
                        String.format("%.1f", cable.delay()),
                        vertecies.get(cable.either()),
                        vertecies.get(cable.other()));

            new mxHierarchicalLayout(graph).execute(parent);
        }
        finally {
            graph.getModel().endUpdate();
        }
        return graph;
    }

    public static void main(String[] args) {
        DataCenterVisualizer frame = new DataCenterVisualizer();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(640, 480);
        frame.setVisible(true);
    }
}